package com.tcxhb.job.agent.server.thread;

import com.tcxhb.job.agent.constants.AgentErrorCode;
import com.tcxhb.job.agent.constants.BestJobConfig;
import com.tcxhb.job.agent.processor.JobProcessorFactory;
import com.tcxhb.job.agent.request.CallbackRequest;
import com.tcxhb.job.agent.service.JobServerApi;
import com.tcxhb.job.common.constants.enums.ExecuteStatus;
import com.tcxhb.job.common.model.MiscResult;
import com.tcxhb.job.common.model.job.JobContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @Description: 任务多线程执行
 * @Auther: tcxhb
 * @Date: 2023/11/8
 */
@Component
@Slf4j
public class JobRunThread {
    @Autowired
    private JobServerApi jobServerApi;
    @Autowired
    private JobProcessorFactory jobProcessorFactory;
    @Autowired
    private BestJobConfig config;
    private ExecutorService threadPool;
    public Map<Long, Integer> statusMaps = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        threadPool = new ThreadPoolExecutor(config.getCoreRunThread(), 10,
                10, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
    }

    /**
     * 提交任务
     *
     * @param context
     * @return
     */
    public MiscResult<Boolean> submit(JobContext context) {
        try {
            //只有任务异常或者为空 才能提交
            Integer status = statusMaps.get(context.getInstanceId());
            if (status != null && !ExecuteStatus.FAIL.eq(status)) {
                return MiscResult.err(AgentErrorCode.AGENT_JOB_STATUS_ERROR);
            }
            //
            log.info("agent-job-submit:{}", context.getInstanceId());
            statusMaps.put(context.getInstanceId(), ExecuteStatus.WAIT_CPU.getType());
            Runner runner = new Runner(context);
            threadPool.submit(runner);
            return MiscResult.suc();
        } catch (Exception e) {
            log.error("agent-job-submit-exp:" + context.getInstanceId(), e);
            statusMaps.put(context.getInstanceId(), ExecuteStatus.FAIL.getType());
            return MiscResult.err(AgentErrorCode.AGENT_JOB_SUBMIT_ERROR);
        }
    }


    public Integer getJobStatus(Long instanceId) {
        return statusMaps.get(instanceId);
    }

    public class Runner extends Thread {
        private JobContext context;

        public Runner(JobContext cxt) {
            this.context = cxt;
        }

        @Override
        public void run() {
            MiscResult result = null;
            try {
                log.info("agent-job-run:{}", context.getInstanceId());
                statusMaps.put(context.getInstanceId(), ExecuteStatus.RUNNING.getType());
                result = jobProcessorFactory.getHandle(context.getJobType()).process(context);
            } catch (Exception e) {
                log.error("agent-job-run-exp:" + context.getInstanceId(), e);
                statusMaps.put(context.getInstanceId(), ExecuteStatus.FAIL.getType());
                result = MiscResult.err(AgentErrorCode.AGENT_JOB_RUN_ERROR);
            } finally {
                //执行成功之后回调状态
                log.info("agent-job-finish:{},{},{}", context.getInstanceId(), result.isSuccess(), result.getCode());
                CallbackRequest request = convert(context, result);
                callback(request);
            }
        }
    }

    /**
     * 结果回调重试3次
     *
     * @param request
     */
    public void callback(CallbackRequest request) {
        try {
            //先请求一次
            for (int i = 0; i < 3; i++) {
                MiscResult<Boolean> result = jobServerApi.callback(request);
                if (result.isSuccess()) {
                    return;
                }
            }
        } catch (Exception e) {
            log.error("agent-job-callback-exp:{},{}", request.getInstanceId(), request.getStatus());
        }
    }

    /**
     * 结果转换
     *
     * @param context
     * @param result
     * @return
     */
    private CallbackRequest convert(JobContext context, MiscResult result) {
        CallbackRequest request = new CallbackRequest(context.getTraceId(), context.getInstanceId());
        if (!result.isSuccess()) {
            //运行失败
            ExecuteStatus status = ExecuteStatus.FAIL;
            request.setStatus(status.getType());
            request.setMsg(result.getMsg());
            statusMaps.put(context.getInstanceId(), status.getType());
        } else {
            //运行成功
            ExecuteStatus status = ExecuteStatus.SUCC;
            request.setStatus(status.getType());
            request.setMsg("success");
            statusMaps.put(context.getInstanceId(), status.getType());
        }
        return request;
    }
}
